import { ComponentType } from 'react'
import { Graph, Node } from '@antv/x6'
import { register } from '@antv/x6-react-shape'
import GraphStore from '@/store/graphStore'
import * as d3 from 'd3'

export const addNodeInCanvas = (inputData: {
  graph: Graph // 目标画布
  // imageID: string // 资产唯一ID
  component: ComponentType<{
    node: Node
    graph: Graph
  }> // 设计资产组件
  size: [number, number]
  position: [number, number] // 添加该组件位于画布的位置
}): Node => {
  const { graph, component, size, position } = inputData

  register({
    shape: 'mark',
    effect: ['data'],
    component: component,
    size: { width: size[0], height: size[1] },
  })

  const newNode = graph.addNode({
    x: position[0], // 默认位置待确认
    y: position[1], // 默认位置待确认
    id: 'mark',
    shape: 'mark',
    // data: { inTrack: false },
  })

  return newNode
}

export const addImageNodeInCanvas = (inputData: {
  graph: Graph // 目标画布
  imageID: string // 资产唯一ID
  component: ComponentType<{
    node: Node
    graph: Graph
  }> // 设计资产组件
  position?: [number, number] // 添加该组件位于画布的位置
}): Node => {
  const { graph, imageID, component, position } = inputData

  register({
    shape: imageID,
    effect: ['data'],
    component: component,
    size: { width: 74, height: 74 },
  })

  const newNode = graph.addNode({
    x: position ? position[0] : 120, // 默认位置待确认
    y: position ? position[1] : 50, // 默认位置待确认
    id: imageID,
    shape: imageID,
    data: { inTrack: false },
  })

  return newNode
}

export const nodeInTrackControl = (graph: Graph, graphStore: GraphStore) => {
  const imageNodeSize = 74 // 图片节点的大小
  const trackPosition = [13, 874] // 轨道的左上坐标位置
  const trackStroke = 90 // 轨道的宽度（高度）
  const inThreshold = 50 // 吸附阈值
  const outThreshold = 60 // 离开阈值

  let test = 0
  graph.on('node:move', ({ e, x, y, node, view }) => {
    if (node.id === 'mark') {
      return
    }
    if (!node.getData()['inTrack']) {
      test = node.position().x
    }
  })
  // y为鼠标在画布中的y值
  graph.on('node:moving', ({ e, x, y, node, view }) => {
    if (node.id === 'mark') {
      node.setPosition(0, 0)
      return
    }
    if (node.position().y < 278) {
      node.setPosition({ ...node.position(), y: 278 })
    }
    if (!node.getData()['inTrack']) {
      // node.setPosition({ ...node.position(), x: test })
    }
    if (y < trackPosition[1] + trackStroke / 2 - outThreshold) {
      if (node.getData()['inTrack']) {
        node.setData({ inTrack: false }, { deep: false, silent: true }) // 浅merge,不触发重绘
        return
      }
    }
    if (
      y >
        trackPosition[1] + trackStroke / 2 - imageNodeSize / 2 - inThreshold &&
      y < trackPosition[1] + trackStroke / 2 - imageNodeSize / 2 + inThreshold
    ) {
      if (!node.getData()['inTrack']) {
        node.setData(
          { inTrack: true, url: node.getData()['url'] },
          { overwrite: true, silent: true }
        ) // 覆盖position,不触发重绘
        graphStore.setImageInTrackMark(true)
      }
    }
    // y方向限制
    if (
      node.getData()['inTrack'] &&
      node.position().y + imageNodeSize / 2 !==
        trackPosition[1] + trackStroke / 2
    ) {
      node.setPosition({
        ...node.position(),
        y: trackPosition[1] + trackStroke / 2 - imageNodeSize / 2,
      })
    }

    // x 方向限制
    if (node.getData()['inTrack']) {
      if (node.position().x < 20) {
        node.setPosition({ ...node.position(), x: 20 })
      } else if (node.position().x > 1062) {
        node.setPosition({ ...node.position(), x: 1062 })
      }
    }
  })
}

// 清空画布中的图片（风格示意图）
export const clearImageInCanvas = (graphStore: GraphStore) => {
  graphStore.graph.getNodes().map((item, _index) => {
    if (item.id !== 'mark') {
      item.remove()
    }
  })
}

// 图像id → 图像url
export const id2url = (id: string) => {
  if (id.includes('http')) {
    return id
  }
  const metas = id.split('-')
  return `https://bosiden-pop.oss-cn-hangzhou.aliyuncs.com/others/style-factory/${metas[0]}/${metas[1]}.png`
}

// 排序放大映射（弥补过拟合问题），将[min, max]放大到 [5, 95]
export const posScale = (resultPos: number[]) => {
  const result = []
  let min = 1
  let max = 0
  for (let i = 0; i < resultPos.length; i++) {
    if (resultPos[i] < min) {
      min = resultPos[i]
    }
    if (resultPos[i] > max) {
      max = resultPos[i]
    }
  }

  // d3 比例尺映射
  const scale = d3.scaleLinear().domain([min, max]).range([0.05, 0.95])
  for (let i = 0; i < resultPos.length; i++) {
    result.push(scale(resultPos[i]))
  }

  return result
}
